import axios, {
  type AxiosInstance,
  AxiosError,
  type AxiosRequestConfig,
  type AxiosResponse
} from 'axios'



import { ElMessage } from 'element-plus'
// 数据返回的接口
// 定义请求响应参数，不含data
// interface Result {
//   code: number
//   msg: string 
// }

// 请求响应参数，包含data ,data传过来的数据类型为什么 T就为什么
interface ResultData<T = any>  {
  errMsg: string 
  errCode:number
  data?:T
}
// 基础路径
const URL: string = 'http://www.eshareedu.cn/fkm/'
enum RequestEnums {
  TIMEOUT = 20000,
  OVERDUE = 600, // 登录失效
  FAIL = 999, // 请求失败
  SUCCESS = 200 // 请求成功
}
const config = {
  // 默认地址
  baseURL: URL as string,
  // 设置超时时间
  timeout: RequestEnums.TIMEOUT as number,
  // 跨域时候允许携带凭证
  withCredentials: false
}

class RequestHttp {
  // 定义成员变量并指定类型
  service: AxiosInstance
  public constructor(config: AxiosRequestConfig) {
    // 实例化axios
    this.service = axios.create(config)

    /**
     * 请求拦截器
     * 客户端发送请求 -> [请求拦截器] -> 服务器
     * token校验(JWT) : 接受服务器返回的token,存储到vuex/pinia/本地储存当中
     */
    this.service.interceptors.request.use(
      (config: AxiosRequestConfig | any) => {
        const token: string = localStorage.getItem('token') || ''
        return {
          ...config,
          headers: {
            Authorization: token // 请求头中携带token信息
          }
        }
      },
      (error: AxiosError) => {
        // 请求报错
        Promise.reject(error)
      }
    )

    /**
     * 响应拦截器
     * 服务器换返回信息 -> [拦截统一处理] -> 客户端JS获取到信息
     */
    this.service.interceptors.response.use(
      (response: AxiosResponse) => {
        // eslint-disable-next-line @typescript-eslint/no-unused-vars
        const { data, config } = response // 解构
        if (data.code === RequestEnums.OVERDUE) {
          // 登录信息失效，应跳转到登录页面，并清空本地的token
          localStorage.setItem('token', '')
          // router.replace({
          //   path: '/login'
          // })
          return Promise.reject(data)
        }
        // 全局错误信息拦截（防止下载文件得时候返回数据流，没有code，直接报错）
        if (data.code && data.code !== RequestEnums.SUCCESS) {
          ElMessage.error(data) // 此处也可以使用组件提示报错信息
          return Promise.reject(data)
        }
        return data
      },
      (error: AxiosError) => {
        const { response } = error
        if (response) {
          this.handleCode(response.status)
        }
        if (!window.navigator.onLine) {
          ElMessage.error('网络连接失败')
          // 可以跳转到错误页面，也可以不做操作
          // return router.replace({
          //   path: '/404'
          // });
        }
      }
    )
  }
  handleCode(code: number): void {
    switch (code) {
      case 401:
        ElMessage.error('登录失败，请重新登录')
        break
      default:
        ElMessage.error('请求失败')
        break
    }
  }

  // 常用方法封装
  get<T>(url: string, params?: object): Promise<ResultData<T>> {
    return this.service.get(url, { params })
  }
  post<T>(url: string, params?: object): Promise<ResultData<T>> {
    return this.service.post(url, params)
  }
  put<T>(url: string, params?: object): Promise<ResultData<T>> {
    return this.service.put(url, params)
  }
  delete<T>(url: string, params?: object): Promise<ResultData<T>> {
    return this.service.delete(url, { params })
  }
}

// 导出一个实例对象
export default new RequestHttp(config)


































// 普通封装
//#region
// AxiosRequestConfig从axios中导出的，将config声明为AxiosRequestConfig，这样我们调用函数时就可以获得TS带来的类型提示
// 泛型T用来指定Reponse类型中result的类型
// function request<T> (config: AxiosRequestConfig):Promise<Response<T>> {
  // 指定promise实例成功之后的回调函数的第一个参数的类型为Response<T>
  // return new Promise<Response<T>>((resolve, reject) => {
    // instance是我们在上面创建的axios的实例
    // 我们指定instance.request函数的第一个泛型为Response，并把Response的泛型指定为函数的泛型T
    // 第二个泛型AxiosResponse的data类型就被自动指定为Response<T>
    // AxiosResponse从axios中导出的，也可以不指定，TS会自动类型推断
    // instance.request<Response<T>>(config)
      // .then((res: AxiosResponse<Response<T>>) => {
      // response类型就是AxiosResponse<Response<T>>，而data类型就是我们指定的Response<T>
      // 请求成功后就我们的数据从response取出并使返回的promise实例的状态变为成功的
      // resolve(res.data)
    // }).catch((error :any) => {
      // 请求失败的处理
      // reject(error)
    // })
  // })
// }
//#endregion